/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package deatax.state;

import deatax.GameData;
import deatax.Improvement;
import deatax.PathInfo;
import deatax.Player;
import deatax.ResourceAmount;
import deatax.Settlement;
import deatax.Tile;
import deatax.display.gui.ContextItem;
import deatax.network.Client;
import deatax.network.Messages;
import deatax.network.NetworkListener;
import deatax.unit.Unit;
import deatax.unit.UnitStack;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JPopupMenu;

/**
 *
 * @author pson
 */
public class TurnState extends GameState implements NetworkListener {

    boolean allow_control;
    TurnMouseListener listener;
    protected JPopupMenu context_menu;

    public TurnState(GameData data) {
        super("Turn", data);
    }

    @Override
    public void begin() {
        allow_control = data.getCurrentPlayer() == data.getSelf() || data.getSelf() == null;
        data.getGui().enableEndTurn(allow_control);
        data.getGui().refreshContent();
        listener = new TurnMouseListener();
        context_menu = new JPopupMenu();
        data.getDisplay().addMouseListener(listener);
        Client.get().addListener(this);
        data.getTray().notifyTray("It's your turn!", true);
    }

    @Override
    public void pause() {
        data.getGui().enableEndTurn(false);
        if (listener != null) {
            data.getDisplay().removeMouseListener(listener);
        }
    }

    @Override
    public void resume() {
        data.getDisplay().addMouseListener(listener);
        data.getGui().enableEndTurn(allow_control);
    }

    @Override
    public void finish() {
        Client.get().removeListener(this);

        data.getMap().setSelectedTile(null);
        data.getGui().setTileInfo(null);
        data.getCurrentPlayer().refreshUnits();
        data.getGui().addMessage(data.getCurrentPlayer(), "Ends turn");

        data.nextPlayerTurn();
        data.getState().popState();
        data.getState().pushState("Roll");
    }

    @Override
    public void die() {
        if (listener != null) {
            data.getDisplay().removeMouseListener(listener);
        }
    }

    private boolean createUnitMenu(Tile tile, Player p) {
        boolean add = false;

        //Movement
        for (UnitStack us : tile.getUnits(p)) {
            if (us.getFreshAmount() > 0) {
                add = true;
                ContextItem item = new ContextItem(tile, us, p, 1);
                item.addActionListener(new MoveListener(us, 1));
                context_menu.add(item);

                if (us.getFreshAmount() > 1) {
                    ContextItem item_all = new ContextItem(tile, us, p, us.getFreshAmount());
                    item_all.addActionListener(new MoveListener(us, us.getFreshAmount()));
                    context_menu.add(item_all);
                }
            }
        }

        return add;
    }

    private boolean createUnitAbilitiesMenu(Tile tile, Player p) {

        boolean add = false;
        for (UnitStack us : tile.getUnits(p)) {
            if (us.getFreshAmount() > 0 && us.getType().hasSkill("settle")) {

                add = true;
                ContextItem item = new ContextItem("Build Settlement", p, null);
                item.addActionListener(new BuildPlaceListener(us, data.getGame().getBaseSettlement()));
                context_menu.add(item);
            }
        }
        return add;
    }

    private boolean createTerrainMenu(Tile tile, Player p) {
        boolean add = false;
        if (tile.getImprovement() == null) {
            if (tile.getOwner() == p) {
                ArrayList<Improvement> imps = tile.getTerrain().getImprovements();
                for (Improvement imp : imps) {
                    //Add a list of possible improvements here
                    if (!(imp instanceof Settlement)) {
                        add = true;
                        ContextItem item = new ContextItem(tile, imp, p);
                        item.addActionListener(new BuildImproveListener(p, tile, imp));
                        context_menu.add(item);
                    }
                }
            } else if (tile.getOwner() == null) {

                //Figure out if can build a port
//                if (tile.getTerrain().getImprovements().contains(data.getGame().getImprove("Port"))) {
//                    ArrayList<Tile> port_tiles = new ArrayList<Tile>();
//                    for (Tile t : p.getTiles()) {
//                        if (t.getImprovement() != null && t.getImprovement() == data.getGame().getImprove("Port")) {
//                            port_tiles.add(t);
//                        }
//                    }
//                    if (!port_tiles.isEmpty()) {
//                        ArrayList<Terrain> ocean_terrain = new ArrayList<Terrain>();
//                        ocean_terrain.add(data.getGame().getTerrain("Ocean"));
//                        ArrayList<Player> player_list = new ArrayList<Player>();
//                        player_list.add(p);
//                        ArrayList<PathInfo> path = data.getMap().findPath(tile, port_tiles, 5, false, p, ocean_terrain, null, null, null, true, player_list, null, true);
//                        if (path != null) {
//                            ContextItem port = new ContextItem(tile, data.getGame().getImprove("Port"), p);
//                            port.addActionListener(new BuildImproveListener(p, tile, data.getGame().getImprove("Port")));
//                            context_menu.add(port);
//                        }
//                    }
//                }

                boolean can_claim = false;
                for (Tile neigh : tile.getNeighbours()) {
                    if (neigh.getOwner() == p) {
                        can_claim = true;
                        break;
                    }
                }

                if (can_claim) {
                    add = true;
                    ArrayList<ResourceAmount> cost = new ArrayList<ResourceAmount>();
                    //Find multiplier for cost based on distance to closest owned settlement
                    ArrayList<PathInfo> path = data.getMap().findPath(tile, p.getSettles(), 5, false, false, p);
                    int multiplier;
                    if (path == null) {
                        multiplier = 5;
                    } else {
                        multiplier = path.get(0).getCost() - 1;
                    }
                    int c;
                    switch (multiplier) {
                        case 0:
                            c = 30;
                            break;
                        case 1:
                            c = 50;
                            break;
                        case 2:
                            c = 80;
                            break;
                        case 3:
                            c = 150;
                            break;
                        default: 
                            c = 250;
                            break;
                    }
                    cost.add(new ResourceAmount(data.getGame().getResource("Money"), c));
                    ContextItem claim_item = new ContextItem("Claim Tile", p, cost);
                    claim_item.addActionListener(new ClaimListener(p, tile, cost));
                    context_menu.add(claim_item);
                }

            }
        }
        return add;
    }

    private boolean createBuildMenu(Tile tile, Player p) {
        boolean add = false;

        if (tile.getImprovement() != null && tile.getOwner() == p) {
            for (Unit u : tile.getImprovement().getUnits()) {
                add = true;
                ContextItem create = new ContextItem(tile, tile.getImprovement(), u, p);
                create.addActionListener(new BuildUnitListener(p, tile, u));
                context_menu.add(create);
            }

        }

        return add;
    }

    private boolean createImproveMenu(Tile tile, Player p) {
        boolean add = false;
        if (tile.getImprovement() != null && tile.getOwner() == p) {
            ArrayList<Improvement> imps = tile.getImprovement().getUpgrades();
            for (Improvement imp : imps) {
                add = true;
                //Add a list of possible improvements here
                ContextItem item = new ContextItem(tile, imp, p);
                item.addActionListener(new BuildImproveListener(p, tile, imp));
                context_menu.add(item);
            }
            if (!(tile.getImprovement() instanceof Settlement)) {
                add = true;
                ContextItem destroy = new ContextItem(tile, null, p);
                destroy.addActionListener(new BuildImproveListener(p, tile, null));
                context_menu.add(destroy);
            }
        }
        return add;
    }

    public void createContextMenu(int x, int y) {
        Tile tile = data.getRender().getHover();
        if (tile != null && tile.getTerrain() != null) {
            context_menu.removeAll();
            Player p = data.getCurrentPlayer();
            //Do unit stuff here
            if (createUnitMenu(tile, p)) {
                context_menu.addSeparator();
            }
            if (createUnitAbilitiesMenu(tile, p)) {
                context_menu.addSeparator();
            }
            if (createTerrainMenu(tile, p)) {
                context_menu.addSeparator();
            }
            if (createBuildMenu(tile, p)) {
                context_menu.addSeparator();
            }
            if (createImproveMenu(tile, p)) {
                context_menu.addSeparator();
            }

            if (context_menu.getComponentCount() > 0) {
                ContextItem item = new ContextItem("Cancel");
                context_menu.add(item);
                //context_menu.setLocation(MouseInfo.getPointerInfo().getLocation());
                int max_width = 0;
                int height = 0;
                for (Component c : context_menu.getComponents()) {
                    Dimension d = c.getPreferredSize();
                    if (d.width > max_width) {
                        max_width = d.width;
                    }
                    height += d.height;
                }
                context_menu.setPopupSize(new Dimension(max_width, height));
                context_menu.show(data.getDisplay(), x, y);
            }
        }
    }

    protected class TurnMouseListener extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getButton() == MouseEvent.BUTTON3) {
                Tile t = data.getRender().getHover();
                data.getMap().setSelectedTile(t);
                data.getGui().setTileInfo(t);
                data.getGui().refreshContent();
                if (t == null) {
                    //data.getGui().closeContextMenu();
                    return;
                }
                if (allow_control) {
                    createContextMenu(e.getX(), e.getY());
                }
            } else if (e.getButton() == MouseEvent.BUTTON1) {
                Tile t = data.getRender().getHover();
                data.getMap().setSelectedTile(t);
                data.getGui().setTileInfo(t);
                data.getGui().refreshContent();
            }
        }

        @Override
        public void mousePressed(MouseEvent e) {
            //data.getGui().closeContextMenu();
        }
    }

    private class MoveListener implements ActionListener {

        private UnitStack stack;
        private int num;

        public MoveListener(UnitStack stack, int num) {
            this.stack = stack;
            this.num = num;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            data.getState().pushState(new UnitMoveState(data, stack, num));
        }
    }
    
    private class BuildPlaceListener implements ActionListener {

        private UnitStack stack;
        private Improvement improve;

        public BuildPlaceListener(UnitStack stack, Improvement improve) {
            this.stack = stack;
            this.improve = improve;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            data.getState().pushState(new BuildingPlaceState(data, stack, improve));
        }
    }

    private class BuildImproveListener implements ActionListener {

        private Player player;
        private Tile tile;
        private Improvement imp;
        private UnitStack stack;

        public BuildImproveListener(Player player, Tile tile, Improvement imp) {
            this.player = player;
            this.tile = tile;
            this.imp = imp;
            this.stack = null;
        }

        public BuildImproveListener(Player player, Tile tile, Improvement imp, UnitStack stack) {
            this.player = player;
            this.tile = tile;
            this.imp = imp;
            this.stack = stack;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String message;
            if (imp == null) {
                message = "Demolishes a " + tile.getImprovement().getName();
            } else {
                message = "Builds a " + imp.getName();
            }
            Client.get().sendMessage(Messages.BUILD, new String[]{(imp == null ? "" : imp.getName()), String.valueOf(tile.getX()), String.valueOf(tile.getY())});
            if (imp != null) {
                ArrayList<String> arg = new ArrayList<String>();
                arg.add(player.getName());
                for (ResourceAmount res : imp.getCosts()) {
                    arg.add(res.getResource().getName());
                    arg.add(String.valueOf(-res.getAmount()));
                }
                Client.get().sendMessage(Messages.RESOURCE, arg);
            }
            if (stack != null) {
                Client.get().sendMessage(Messages.UNIT, new String[]{player.getName(), stack.getType().getName(), "1", String.valueOf(tile.getX()), String.valueOf(tile.getY())});
            }
            Client.get().sendMessage(Messages.LOG, new String[]{player.getName(), message});
        }
    }

    private class BuildUnitListener implements ActionListener {

        private Player player;
        private Tile tile;
        private Unit unit;

        public BuildUnitListener(Player player, Tile tile, Unit unit) {
            this.player = player;
            this.tile = tile;
            this.unit = unit;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String message = "Builds a " + unit.getName();
            Client.get().sendMessage(Messages.UNIT, new String[]{player.getName(), unit.getName(), "1", String.valueOf(tile.getX()), String.valueOf(tile.getY())});
            //tile.addUnit(player, unit, 1);
            ArrayList<String> arg = new ArrayList<String>();
            arg.add(player.getName());
            for (ResourceAmount res : unit.getCost()) {
                arg.add(res.getResource().getName());
                arg.add(String.valueOf(-res.getAmount()));
            }
            Client.get().sendMessage(Messages.RESOURCE, arg);

//            for (ResourceAmount res : unit.getCost()) {
//                player.addResource(res.getResource(), -res.getAmount());
//            }
            Client.get().sendMessage(Messages.POPULATION, new String[]{String.valueOf(tile.getX()), String.valueOf(tile.getY()), String.valueOf(-unit.getPopulationCost())});
            //tile.addPopulation(-unit.getPopulationCost());
            Client.get().sendMessage(Messages.LOG, new String[]{player.getName(), message});

//            data.getGui().addMessage(player, message);
//            data.getGui().refreshGui();
        }
    }

    private class ClaimListener implements ActionListener {

        Player player;
        Tile tile;
        ArrayList<ResourceAmount> cost;

        public ClaimListener(Player player, Tile tile, ArrayList<ResourceAmount> cost) {
            this.player = player;
            this.tile = tile;
            this.cost = cost;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String message = "Claims a " + tile.getTerrain().getName() + " tile";
            //tile.setOwner(player);
            Client.get().sendMessage(Messages.CLAIM, new String[]{player.getName(), String.valueOf(tile.getX()), String.valueOf(tile.getY())});
            ArrayList<String> arg = new ArrayList<String>();
            arg.add(player.getName());
            for (ResourceAmount res : cost) {
                arg.add(res.getResource().getName());
                arg.add(String.valueOf(-res.getAmount()));
            }
            Client.get().sendMessage(Messages.RESOURCE, arg);
            Client.get().sendMessage(Messages.LOG, new String[]{player.getName(), message});

            //data.getGui().addMessage(player, message);
//            data.getGui().refreshGui();
        }
    }

    @Override
    public void processMessage(int type, String[] arg) {
        System.out.println("Turn");
        commonMessages(type, arg);
    }
}
